home *** CD-ROM | disk | FTP | other *** search
/ Logiciels PC Special 3 / Logiciel PC - Hors-Serie 3.iso / Logs / micros / ql / outils / qltoolsq / source / qltools.c < prev    next >
C/C++ Source or Header  |  1998-05-18  |  42KB  |  2,200 lines

  1. /***************************************************************************
  2.  * QLTOOLS
  3.  *
  4.  * Read a QL floppy disk
  5.  *
  6.  * (c)1992 by Giuseppe Zanetti
  7.  *
  8.  * Giuseppe Zanetti
  9.  * via Vergani, 11 - 35031 Abano Terme (Padova) ITALY
  10.  * e-mail: beppe@sabrina.dei.unipd.it
  11.  *
  12.  * Valenti Omar
  13.  * via Statale,127 - 42013 Casalgrande (REGGIO EMILIA) ITALY
  14.  * e-mail: sinf7@imovx2.unimo.it
  15.  * sinf7@imoax1.unimo.it
  16.  * sinf@c220.unimo.it
  17.  *
  18.  * somewhat hacked by Richard Zidlicky, added formatting, -dl, -x option
  19.  * rdzidlic@cip.informatik.uni-erlangen.de
  20.  *
  21.  * Seriously major rewrite (c) Jonathan R Hudson to support level 2
  22.  * sub-directories, fix some bugs and make the code IMHO :-) rather more
  23.  * maintainable. Split system specific code into individual directories and
  24.  * added code for NT and OS2.
  25.  *
  26.  * $Log: qltools.c,v $
  27.  * Revision 2.11  1996/07/14  11:57:07  jrh
  28.  * Tidied up code
  29.  *
  30.  * Revision 2.10  1996/07/14  10:28:58  jrh
  31.  * added extra info messages
  32.  *
  33.  * Revision 2.9  1995/11/29  18:34:53  root
  34.  * Changed output routine to correctly decide if an XTcc block was
  35.  * required.
  36.  *
  37.  * Revision 2.8  1995/10/22  14:11:36  root
  38.  * Added VMS support
  39.  *
  40.  * Revision 2.7  1995/10/22  14:02:42  root
  41.  * Added zeroing of some sectors
  42.  *
  43.  * Revision 2.6  1995/09/21  17:01:03  root
  44.  * Release version 2.4
  45.  *
  46.  * Revision 2.5  1995/09/18  13:13:59  root
  47.  * Full support for Level 2 directories
  48.  *
  49.  * Revision 2.4  1995/09/16  18:56:48  root
  50.  * Placeholder, system specific code in
  51.  *
  52.  * Revision 2.3  1995/09/09  16:38:08  root
  53.  * Added data structures for disk objects (directories, block 0 etc)
  54.  * Did I fix a few more bugs too ?
  55.  *
  56.  * Revision 2.2  1995/09/06  12:13:17  root
  57.  * Fixed null version record in DOS, and some other bugs
  58.  *
  59.  * Revision 2.1  1995/09/06  12:11:26  root
  60.  * Initial jh version, fixed lots of bugs
  61.  *
  62.  ****************************************************************************/
  63.  
  64. static char rcsid[] = "$Id: qltools.c,v 2.11 1996/07/14 11:57:07 jrh Exp $";
  65.  
  66. #if defined (__OS2__) || defined (__NT__) || defined  (__MSDOS__)
  67. # define DOS_LIKE
  68. #endif
  69.  
  70. #include <stdio.h>
  71. #include <stdlib.h>
  72. #include <fcntl.h>
  73. #include <string.h>
  74. #include <ctype.h>
  75. #include <sys/stat.h>
  76. #include "qltools.h"
  77.  
  78. /* -------------------------- globals ----------------------------------- */
  79. int gsides, gtracks, gsectors, goffset, allocblock, gclusters, gspcyl;
  80. BLOCK0 *b0;
  81.  
  82. /* -------------------------- 'local' globals --------------------------- */
  83. static HANDLE fd;
  84. static SDL *SList = NULL;    /* sub-directory list */
  85. static unsigned int bleod;    /* directory block offset */
  86. static unsigned int byeod;    /*           bytes        */
  87. static QLDIR *pdir;        /* memory image of directory */
  88. static long err;
  89. static short tranql = 1;
  90. static short list = 0;
  91. static int ql5a;        /* flag */
  92. static int block_dir[64];
  93. static int block_max = 0;
  94. static long lac = 0;        /* last allocated cluster */
  95. static time_t timeadjust;
  96. static char OWopt = 0;
  97.  
  98. /* -------------------------- Prototypes ------------------------------- */
  99. void write_cluster (void *, int);
  100. int read_cluster (void *, int);
  101. void make_convtable (int);
  102. int print_entry (QLDIR *, int, void *);
  103. void free_cluster (long);
  104. int alloc_new_cluster (int, int, short);
  105. void format (char *, char *);
  106. void dir_write_back (QLDIR *, SDL *, short *);
  107. void set_header (int, long, QLDIR *, SDL *);
  108. void read_b0fat (int);
  109. void write_b0fat (void);
  110. void read_fat (void);
  111. void read_dir (void);
  112. void print_map (void);
  113. int RecurseDir (int, long, void *, int (*func) (QLDIR *, int, void *));
  114. int find_free_cluster (void);
  115.  
  116. void *xmalloc (long alot)
  117. {
  118.     void *p = calloc (alot, 1);
  119.  
  120.     if (p == NULL)
  121.     {
  122.     perror ("! :");
  123.     exit (0);
  124.     }
  125.     return p;
  126. }
  127.  
  128.  
  129. /* --------------------- byte order conversion --------------------------- */
  130.  
  131. ushort inline swapword (ushort val)
  132. {
  133.     return (ushort) (val << 8) + (val >> 8);
  134. }
  135.  
  136. ulong inline swaplong (ulong val)
  137. {
  138.     return (ulong) (((ulong) swapword (val & 0xFFFF) << 16) |
  139.             (ulong) swapword (val >> 16));
  140. }
  141.  
  142. static inline int maxdir (void)
  143. {
  144.     return (byeod >> 6) + (bleod * DIRSBLK);
  145. }
  146.  
  147. ushort inline fat_file (ushort cluster)
  148. {
  149.     unchar *base = b0->map + cluster * 3;
  150.  
  151.     return (ushort) (*base << 4) + (ushort) ((*(base + 1) >> 4) & 15);
  152. }
  153.  
  154. ushort inline fat_cl (ushort cluster)
  155. {
  156.     unchar *base = b0->map + cluster * 3;
  157.  
  158.     return (*(base + 1) & 15) * 256 + *(base + 2);
  159. }
  160.  
  161. void inline set_fat_file (ushort cluster, ushort file)
  162. {
  163.     unchar *base = b0->map + cluster * 3;
  164.  
  165.     *base = file >> 4;
  166.     *(base + 1) = ((file & 15) << 4) | (*(base + 1) & 15);
  167. }
  168.  
  169. void inline set_fat_cl (ushort cluster, ushort clnum)
  170. {
  171.     unchar *base = b0->map + cluster * 3;
  172.  
  173.     *(base + 1) = (clnum >> 8) | (*(base + 1) & (~15));
  174.     *(base + 2) = clnum & 255;
  175. }
  176.  
  177.  
  178. ushort inline FileXDir(ushort fnum)
  179. {
  180.     ushort fno = 0;
  181.     if(fnum)
  182.     {
  183.     fno = swapword(fnum) - 1;
  184.     }
  185.     return fno;
  186. }
  187.  
  188. inline QLDIR *GetEntry (int fn)
  189. {
  190.     QLDIR *entry;
  191.  
  192.     if (fn & 0x800)
  193.     {
  194.     entry = NULL;
  195.     }
  196.     else
  197.     {
  198.     entry = pdir + fn;
  199.     }
  200.     return entry;
  201. }
  202.  
  203. short FindCluster (ushort fnum, ushort blkno)
  204. {
  205.     ushort file, blk;
  206.     short i;
  207.  
  208.     for (i = 0; i < gclusters; i++)
  209.     {
  210.     file = fat_file (i);
  211.     blk = fat_cl (i);
  212.     if (file == fnum && blk == blkno)
  213.     {
  214.         break;
  215.     }
  216.     }
  217.     return (i == gclusters) ? -1 : i;
  218. }
  219.  
  220. void cat_file (long fnum, QLDIR * entry)
  221. {
  222.     long flen;
  223.     int i, ii, s, start, end;
  224.     long qldata = 0;
  225.  
  226. #ifdef DOS_LIKE
  227.     setmode (fileno (stdout), O_BINARY);
  228. #endif
  229.  
  230.     if(entry->d_type == 255)
  231.     {
  232.     write(1, QLDIRSTRING, 16);
  233.     }
  234.     else
  235.     {
  236.     flen = swaplong (entry->d_length);    /* with the header */
  237.     if (entry->d_type == 1)
  238.     {
  239.         qldata = entry->d_datalen;
  240.     }
  241.  
  242.     if (flen + swapword (entry->d_szname) == 0)
  243.     {
  244.         fputs ("warning: file appears to be deleted\n", stderr);
  245.     }
  246.     else
  247.     {
  248.         char *buffer = xmalloc (512 * allocblock);
  249.         long lblk = flen / (GSSIZE * allocblock);
  250.         long xblk = 0,xbyt = 0;
  251.         short needx = 1;
  252.  
  253.         if(qldata)
  254.         {
  255.         xblk = (flen - 8) / (GSSIZE * allocblock);
  256.         xbyt = (flen - 8) % (GSSIZE * allocblock);
  257.         }
  258.  
  259.         for (s = 0; s <= lblk; s++)
  260.         {
  261.         if ((i = FindCluster (fnum, s)) != -1)
  262.         {
  263.             read_cluster (buffer, i);
  264.             if (s == 0)
  265.             start = 64;
  266.             else
  267.             start = 0;
  268.             end = GSSIZE * allocblock;
  269.             if (s == lblk)
  270.             end = flen % (GSSIZE * allocblock);
  271.             err = write (1, buffer + start, end - start);
  272.             if (err < 0)
  273.             perror ("output file: write(): ");
  274.             if(qldata && s == xblk)
  275.             {
  276.             needx = memcmp(buffer+start+xbyt, "XTcc", 4);
  277.             }
  278.         }
  279.         else
  280.         {
  281.             fprintf (stderr, "** Cluster #%d of %.*s not found **\n",
  282.                  s, entry->d_szname, entry->d_name);
  283.             err = lseek (1, GSSIZE * allocblock, SEEK_CUR);
  284.             /* leave hole */
  285.             if (err < 0)    /* non seekable */
  286.             for (ii = 0; ii < allocblock * GSSIZE; ii++)
  287.                 fputc ('#', stdout);
  288.         }
  289.         }
  290.         free (buffer);
  291.  
  292.         if (qldata && needx)
  293.         {
  294.         static struct
  295.         {
  296.             union
  297.             {
  298.             char xtcc[4];
  299.             long x;
  300.             } x;
  301.             long dlen;
  302.         } xtcc =  {{"XTcc"}, 0};
  303.         xtcc.dlen = qldata;
  304.         write(1, &xtcc, 8);
  305.         }
  306.     }
  307.     }
  308. }
  309.  
  310. void dump_file (long fnum, QLDIR * entry)
  311. {
  312.     long flen;
  313.     int i, ii, s, start, end;
  314.     long qldata = 0;
  315.  
  316.     short j,k;
  317.     char fname[37];
  318.     FILE *f;
  319.  
  320.     j = k = swapword (entry->d_szname);
  321.     sprintf (fname,"%-*.*s\0", k, j, entry->d_name);
  322.  
  323.     f=fopen(fname,"wb");
  324.     if (f==NULL) {
  325.         fprintf(stderr,"Cannot open file %s for writing\n",fname);
  326.         exit(1);
  327.     }
  328.  
  329.     if(entry->d_type == 255)
  330.     {
  331.     fwrite(QLDIRSTRING, 1, 16, f);
  332.     }
  333.     else
  334.     {
  335.     flen = swaplong (entry->d_length);    /* with the header */
  336.     if (entry->d_type == 1)
  337.     {
  338.         qldata = entry->d_datalen;
  339.     }
  340.  
  341.     if (flen + swapword (entry->d_szname) == 0)
  342.     {
  343.         fputs ("warning: file appears to be deleted\n", stderr);
  344.     }
  345.     else
  346.     {
  347.         char *buffer = xmalloc (512 * allocblock);
  348.         long lblk = flen / (GSSIZE * allocblock);
  349.         long xblk = 0,xbyt = 0;
  350.         short needx = 1;
  351.  
  352.         if(qldata)
  353.         {
  354.         xblk = (flen - 8) / (GSSIZE * allocblock);
  355.         xbyt = (flen - 8) % (GSSIZE * allocblock);
  356.         }
  357.  
  358.         for (s = 0; s <= lblk; s++)
  359.         {
  360.         if ((i = FindCluster (fnum, s)) != -1)
  361.         {
  362.             read_cluster (buffer, i);
  363.             if (s == 0)
  364.             start = 64;
  365.             else
  366.             start = 0;
  367.             end = GSSIZE * allocblock;
  368.             if (s == lblk)
  369.             end = flen % (GSSIZE * allocblock);
  370.             err = fwrite (buffer + start, 1, end - start, f);
  371.             if (err < 0)
  372.             perror ("output file: write(): ");
  373.             if(qldata && s == xblk)
  374.             {
  375.             needx = memcmp(buffer+start+xbyt, "XTcc", 4);
  376.             }
  377.         }
  378.         else
  379.         {
  380.             fprintf (stderr, "** Cluster #%d of %.*s not found **\n",
  381.                  s, entry->d_szname, entry->d_name);
  382.             err = lseek (1, GSSIZE * allocblock, SEEK_CUR);
  383.             /* leave hole */
  384.             if (err < 0)    /* non seekable */
  385.             for (ii = 0; ii < allocblock * GSSIZE; ii++)
  386.                 fputc ('#', f);
  387.         }
  388.         }
  389.         free (buffer);
  390.  
  391.         if (qldata && needx)
  392.         {
  393.         static struct
  394.         {
  395.             union
  396.             {
  397.             char xtcc[4];
  398.             long x;
  399.             } x;
  400.             long dlen;
  401.         } xtcc =  {{"XTcc"}, 0};
  402.         xtcc.dlen = qldata;
  403.         fwrite(&xtcc, 1, 8, f);
  404.         }
  405.     }
  406.     }
  407.     fclose(f);
  408. }
  409.  
  410. void UpdateSubEntry (QLDIR * entry, SDL * sdl, short *off)
  411. {
  412.  
  413.     int s, start, end;
  414.     int i, j;
  415.     int rval = 0;
  416.     long flen = sdl->flen;
  417.     short fnum = sdl->fileno;
  418.     unchar *buffer = xmalloc (GSSIZE * allocblock);
  419.  
  420.     if (off)
  421.     {
  422.     s = (*off) / (GSSIZE * allocblock);
  423.     j = (*off) % (GSSIZE * allocblock);
  424.     if ((i = FindCluster (fnum, s)) != -1)
  425.     {
  426.         if (flen != 128 && j != 64)
  427.         {
  428.         read_cluster (buffer, i);
  429.         }
  430.         memcpy ((buffer + j), entry, 64);
  431.         write_cluster (buffer, i);
  432.     }
  433.     }
  434.     else
  435.     {
  436.     for (s = 0; !rval && s <= flen / (GSSIZE * allocblock); s++)
  437.     {
  438.         i = FindCluster (fnum, s);
  439.         if (i != -1)
  440.         {
  441.         read_cluster (buffer, i);
  442.         if (s == 0)
  443.             start = 64;
  444.         else
  445.             start = 0;
  446.         end = GSSIZE * allocblock;
  447.  
  448.         if (s == (flen / (GSSIZE * allocblock)))
  449.             end = (flen % (GSSIZE * allocblock));
  450.         else
  451.             end = GSSIZE * allocblock;
  452.         for (j = start; j <= end; j += 64)
  453.         {
  454.             QLDIR *ent = (QLDIR *) (buffer + j);
  455.  
  456.             if (ent->d_fileno == entry->d_fileno)
  457.             {
  458.             if (entry->d_szname == 0 && entry->d_length == 0)
  459.             {
  460.                 memset (ent, '\0', 64);
  461.             }
  462.             else
  463.             {
  464.                 memcpy (ent, entry, 64);
  465.             }
  466.             write_cluster (buffer, i);
  467.             rval = 1;
  468.             break;
  469.             }
  470.         }
  471.         }
  472.     }
  473.     }
  474.     free (buffer);
  475. }
  476.  
  477. void RemoveList (SDL * sdl)
  478. {
  479.     SDL *prev = NULL, *sl;
  480.  
  481.     for (sl = SList; sl; prev = sl, sl = sl->next)
  482.     {
  483.     if (sdl == sl)
  484.     {
  485.         if (prev == NULL)
  486.         {
  487.         SList = sl->next;
  488.         }
  489.         else
  490.         {
  491.         prev->next = sl->next;
  492.         }
  493.         free (sl);
  494.         sl = NULL;
  495.         break;
  496.     }
  497.     }
  498. }
  499.  
  500.  
  501. int CountDir (QLDIR * e, int fnum, COUNT_S *s)
  502. {
  503.     long len;
  504.  
  505.     if (((len = e->d_length) != 0) &&  (e->d_szname != 0))
  506.     {
  507.     s->nfiles++;
  508.     }
  509.  
  510.     if (s->rflag == 0)
  511.     {
  512.     s->indir++;
  513.     if (len == 0 && s->freed == 0)
  514.     {
  515.         s->freed = s->indir;
  516.     }
  517.     }
  518.     else if (e->d_type == 255)
  519.     {
  520.     RecurseDir (fnum, swaplong (e->d_length), s,
  521.             (int (*) (QLDIR *, int, void *)) CountDir);
  522.     }
  523.     return 0;
  524. }
  525.  
  526. void del_file (long fnum, QLDIR * entry, SDL * sdl)
  527. {
  528.     long int flen, file;
  529.     int i, freed, blk0;
  530.     short rdir = 0;
  531.     COUNT_S nf;
  532.  
  533.     nf.nfiles = 0;
  534.     nf.rflag = 1;
  535.  
  536.     if (entry->d_type == 255)
  537.     {
  538.     RecurseDir (fnum, swaplong (entry->d_length), &nf,
  539.             (int (*) (QLDIR *, int, void *)) CountDir);
  540.     if (nf.nfiles)
  541.     {
  542.         fprintf (stderr, "Directory must be empty to delete (%d)\n",
  543.              nf.nfiles);
  544.         exit (0);
  545.     }
  546.     else
  547.     {
  548.         rdir = 1;
  549.     }
  550.     }
  551.  
  552.     freed = 0;
  553.     blk0 = -1;
  554.  
  555.     flen = swaplong (entry->d_length);
  556.     if (flen == 0)
  557.     {
  558.     fprintf (stderr, "file already deleted?\n");
  559.     exit (1);
  560.     }
  561.  
  562.     for (i = 1; i < gclusters; i++)
  563.     {
  564.     file = fat_file (i);
  565.     if (file == fnum)
  566.     {
  567.         if (fat_cl (i) == 0)
  568.         blk0 = i;
  569.         free_cluster (i);
  570.         freed++;
  571.     }
  572.     }
  573.  
  574.     b0->q5a_free = swapword (freed * allocblock + swapword (b0->q5a_free));
  575.  
  576.     entry->d_szname = 0;
  577.     entry->d_length = 0;
  578.     entry->d_type = 0;
  579.  
  580.     if (blk0 > 0)
  581.     {
  582.     unchar *b = xmalloc (512 * allocblock);
  583.  
  584.     read_cluster (b, blk0);
  585.     memcpy (b, entry, 64);
  586.     write_cluster (b, blk0);
  587.     free (b);
  588.     }
  589.     else
  590.     fprintf (stderr, "block 0 of file missing??\n");
  591.  
  592.     write_b0fat ();        /* write_cluster(b0,0); */
  593.     dir_write_back (entry, sdl, NULL);
  594.     if (rdir)
  595.     {
  596.     RemoveList (sdl);
  597.     }
  598. }
  599.  
  600. void usage (char *error)
  601. {
  602.     static char *options[] =
  603.     {
  604.     "Usage: qltools dev -[options] [filename]\n",
  605.     "options:",
  606.     "    -q         dump files in qlay(w) format and update qlay.dir",
  607.     "    -d         list directory          -s         list short directory",
  608.     "    -i         list info               -m         list disk map",
  609.     "    -c         list conversion table   -l         list files on write",
  610.     "    -w <files> write files (query)     -W <files> (over)write files",
  611.     "    -r <name>  remove file <name>      -n <file>  copy <file> to stdout",
  612.     "    -uN        ASCII dump cluster N    -UN        binary dump",
  613.     "    -M <name>  Make level 2 directory <name>\n",
  614.     "    -x <name> <size> make <name> executable with dataspace <size>",
  615.     "    -fxx <name> format as xx=hd|dd disk with label <name>\n",
  616.     "  QLTOOLS for " OSNAME " (version " VERSION ")",
  617.     "  dev is either a file with the image of a QL format disk",
  618.     "  or a floppy drive with a SMS/QDOS disk inserted in it (e.g. " FDNAME ")\n",
  619.     "  by Giuseppe Zanetti,Valenti Omar,Richard Zidlicky & Jonathan Hudson",
  620.     NULL};
  621.     char **h;
  622.  
  623.     fprintf (stderr, "error : %s\n", error);
  624.     for( h = options; *h; h++)
  625.     {
  626.     fputs(*h, stderr);
  627.     fputc('\n', stderr);
  628.     }
  629.     exit (1);
  630. }
  631.  
  632. void print_info (void)
  633. {
  634.     short i;
  635.  
  636.     printf ("Disk ID          : %.4s\n", b0->q5a_id);
  637.     printf ("Disk Label       : %.10s\n", b0->q5a_mnam);
  638.     printf ("sectors per track: %i\n", gsectors);
  639.     printf ("sectors per cyl. : %i\n", gspcyl);
  640.     printf ("number of cylind.: %i\n", gtracks);
  641.     printf ("allocation block : %i\n", allocblock);
  642.     printf ("sector offset/cyl: %i\n", goffset);
  643.     printf ("random           : %04x\n", swapword (b0->q5a_rand));
  644.     printf ("Updates          : %ld\n", swaplong (b0->q5a_mupd));
  645.     printf ("free sectors     : %i\n", swapword (b0->q5a_free));
  646.     printf ("good sectors     : %i\n", swapword (b0->q5a_good));
  647.     printf ("total sectors    : %i\n", swapword (b0->q5a_totl));
  648.  
  649.     printf ("directory is     : %u sectors and %u bytes\n", bleod, byeod);
  650.  
  651.     printf ("\nlogical-to-physical sector mapping table:\n\n");
  652.     for (i = 0; i < gspcyl; i++)
  653.     printf ("%x ", b0->q5a_lgph[i]);
  654.     putc ('\n', stdout);
  655.  
  656.     if (ql5a)
  657.     {
  658.     printf ("\nphysical-to-logical sector mapping table:\n\n");
  659.     for (i = 0; i < gspcyl; i++)
  660.         printf ("%x ", b0->q5a_phlg[i]);
  661.     }
  662.     putc ('\n', stdout);
  663. }
  664.  
  665. int RecurseDir (int fnum, long flen, void *parm, int (*func) (QLDIR *, int, void *))
  666. {
  667.     int s, start, end;
  668.     int i, j;
  669.     int rval = 0;
  670.  
  671.     if (flen > 64)
  672.     {
  673.     unchar *buffer = xmalloc (GSSIZE * allocblock);
  674.  
  675.     for (s = 0; s <= flen / (GSSIZE * allocblock); s++)
  676.     {
  677.  
  678.         i = FindCluster (fnum, s);
  679.         if (i != -1)
  680.         {
  681.         read_cluster (buffer, i);
  682.         if (s == 0)
  683.             start = 64;
  684.         else
  685.             start = 0;
  686.         end = GSSIZE * allocblock;
  687.  
  688.         if (s == (flen / (GSSIZE * allocblock)))
  689.             end = (flen % (GSSIZE * allocblock));
  690.         else
  691.             end = GSSIZE * allocblock;
  692.         for (j = start; j <= end; j += 64)
  693.         {
  694.             QLDIR *ent = (QLDIR *) (buffer + j);
  695.             int fno = FileXDir(ent->d_fileno);
  696.             if ((rval = (func) (ent, fno, parm)) != 0)
  697.             {
  698.             break;
  699.             }
  700.         }
  701.         }
  702.     }
  703.     free (buffer);
  704.     }
  705.     else
  706.     {
  707.     rval = 1;
  708.     }
  709.     return rval;
  710. }
  711.  
  712. int print_entry (QLDIR * entry, int fnum, void *flag)
  713. {
  714.     short j,k;
  715.     long flen;
  716.  
  717.     if (entry == NULL)
  718.     return 0;
  719.  
  720.     flen = swaplong (entry->d_length);
  721.  
  722.     if (flen + swapword (entry->d_szname) == 0)
  723.     return 0;
  724.  
  725.     j = k = swapword (entry->d_szname);
  726.     if (*((short *) flag) == 0)
  727.     {
  728.     k = 36;
  729.     }
  730.     printf ("%-*.*s", k, j, entry->d_name);
  731.  
  732.     if (entry->d_type == 255)
  733.     {
  734.     if (*((short *) flag))
  735.     {
  736.         putc ('\n', stdout);
  737.     }
  738.     else
  739.     {
  740.         if (*((short *) flag) == 0)
  741.         {
  742.         printf ("(dir) %ld\n", flen - 64l);
  743.         }
  744.     }
  745.     if(*((short *)flag) != 2)
  746.     {
  747.         RecurseDir (fnum, flen, flag, print_entry);
  748.     }
  749.  
  750.     }
  751.     else if (*((short *) flag) == 0)
  752.     {
  753.     switch (entry->d_type)
  754.     {
  755.         case 0:
  756.         fputs (" ", stdout);
  757.         break;
  758.         case 1:
  759.         fputs ("E", stdout);
  760.         break;
  761.         case 2:
  762.         fputs ("r", stdout);
  763.         break;
  764.         default:
  765.         printf ("%3d", entry->d_type);
  766.         break;
  767.     }
  768.     printf (" %7ld", (long) (flen - 64L));
  769.     {
  770.         struct tm *tm;
  771.         time_t t = swaplong (entry->d_update) - TIME_DIFF - timeadjust;
  772.  
  773.         tm = localtime (&t);
  774.         printf (" %02d/%02d/%02d %02d:%02d:%02d v%-5u",
  775.             tm->tm_mday, tm->tm_mon + 1, tm->tm_year,
  776.             tm->tm_hour, tm->tm_min, tm->tm_sec,
  777.             swapword (entry->d_version));
  778.     }
  779.     if (entry->d_type == 1 && entry->d_datalen)
  780.     {
  781.         printf (" (%ld)", swaplong (entry->d_datalen));
  782.     }
  783.     putc ('\n', stdout);
  784.     }
  785.     else
  786.     {
  787.     putc ('\n', stdout);
  788.     }
  789.     return 0;
  790. }
  791.  
  792. void print_dir (short flag)
  793. {
  794.     int d;
  795.     QLDIR *entry;
  796.  
  797.     if (flag == 0)
  798.     {
  799.     printf ("%.10s\n", b0->q5a_mnam);
  800.     printf ("%i/%i sectors.\n\n",
  801.         swapword (b0->q5a_free), swapword (b0->q5a_good));
  802.     }
  803.  
  804.     for (d = 1; d < maxdir (); d++)
  805.     {
  806.     entry = pdir + d;
  807.     if (swaplong (entry->d_length) + swapword (entry->d_szname) != 0)
  808.     {
  809.         print_entry (entry, d, &flag);
  810.     }
  811.     }
  812. }
  813.  
  814. void qlay_dir(char *p)
  815. {
  816. int    i;
  817. FILE    *qldf;
  818. int    number,slen,nof;
  819.  
  820.     if ((qldf=fopen("qlay.dir","ab")) == NULL) {
  821.         fprintf(stderr,"Cannot open %s\n\n","qlay.dir");
  822.         exit(1);
  823.     }
  824.  
  825.     for(i=0;i<64;i++) fputc(*p++,qldf);
  826.     fclose(qldf);
  827. }
  828.  
  829. int dump_entry (QLDIR * entry, int fnum, void *flag)
  830. {
  831.     short j,k;
  832.     long flen;
  833.  
  834.     if (entry == NULL)
  835.     return 0;
  836.  
  837.     flen = swaplong (entry->d_length);
  838.  
  839.     if (flen + swapword (entry->d_szname) == 0)
  840.     return 0;
  841.  
  842.     j = k = swapword (entry->d_szname);
  843.     if (*((short *) flag) == 0)
  844.     {
  845.     k = 36;
  846.     }
  847.     printf ("%-*.*s", k, j, entry->d_name);
  848.  
  849.     if (entry->d_type == 255)
  850.     {
  851.     if (*((short *) flag))
  852.     {
  853.         putc ('\n', stdout);
  854.     }
  855.     else
  856.     {
  857.         if (*((short *) flag) == 0)
  858.         {
  859.         printf ("(dir) %ld\n", flen - 64l);
  860.         }
  861.     }
  862.     if(*((short *)flag) != 2)
  863.     {
  864.         RecurseDir (fnum, flen, flag, dump_entry);
  865.     }
  866.  
  867.     }
  868.     else if (*((short *) flag) == 0)
  869.     {
  870.     switch (entry->d_type)
  871.     {
  872.         case 0:
  873.         fputs (" ", stdout);
  874.         break;
  875.         case 1:
  876.         fputs ("E", stdout);
  877.         break;
  878.         case 2:
  879.         fputs ("r", stdout);
  880.         break;
  881.         default:
  882.         printf ("%3d", entry->d_type);
  883.         break;
  884.     }
  885.     printf (" %7ld", (long) (flen - 64L));
  886.     {
  887.         struct tm *tm;
  888.         time_t t = swaplong (entry->d_update) - TIME_DIFF - timeadjust;
  889.  
  890.         tm = localtime (&t);
  891.         printf (" %02d/%02d/%02d %02d:%02d:%02d v%-5u",
  892.             tm->tm_mday, tm->tm_mon + 1, tm->tm_year,
  893.             tm->tm_hour, tm->tm_min, tm->tm_sec,
  894.             swapword (entry->d_version));
  895.     }
  896.     if (entry->d_type == 1 && entry->d_datalen)
  897.     {
  898.         printf (" (%ld)", swaplong (entry->d_datalen));
  899.     }
  900.     putc ('\n', stdout);
  901.     fflush(stdout);
  902.     dump_file(fnum,entry);
  903.     qlay_dir((char*)entry);
  904.     }
  905.     else
  906.     {
  907.     putc ('\n', stdout);
  908.     }
  909.     return 0;
  910. }
  911.  
  912. void dump_dir (short flag)
  913. {
  914.     int d;
  915.     QLDIR *entry;
  916.  
  917.     if (flag == 0)
  918.     {
  919.     printf ("%.10s\n", b0->q5a_mnam);
  920.     printf ("%i/%i sectors.\n\n",
  921.         swapword (b0->q5a_free), swapword (b0->q5a_good));
  922.     }
  923.  
  924.     for (d = 1; d < maxdir (); d++)
  925.     {
  926.     entry = pdir + d;
  927.     if (swaplong (entry->d_length) + swapword (entry->d_szname) != 0)
  928.     {
  929.         dump_entry (entry, d, &flag);
  930.     }
  931.     }
  932. }
  933.  
  934. void make_convtable (int verbose)
  935. {
  936.     int i, si, tr, se, uxs, sectors;
  937.  
  938.     if (verbose)
  939.     {
  940.     printf ("\nCONVERSION TABLE\n\n");
  941.     printf ("logic\ttrack\tside\tsector\tunix_dev\n\n");
  942.     }
  943.  
  944.     sectors = gclusters * allocblock;
  945.  
  946.     if (verbose)
  947.     {
  948.     for (i = 0; i < sectors; i++)
  949.     {
  950.         tr = LTP_TRACK (i);
  951.         si = LTP_SIDE (i);
  952.         se = LTP_SCT (i);
  953.         uxs = tr * gspcyl + gsectors * si + se;
  954.         if (verbose)
  955.         {
  956.         printf ("%i\t%i\t%i\t%i\t%i\n", i, tr, si, se, uxs);
  957.         }
  958.     }
  959.     }
  960. }
  961.  
  962. void dump_cluster (int num, short flag)
  963. {
  964.     int i, sect;
  965.     unsigned char buf[512];
  966.  
  967.     for (i = 0; i < allocblock; i++)
  968.     {
  969.     short j, k;
  970.     unsigned char *p;
  971.     long fpos=0;
  972.  
  973.     sect = num * allocblock + i;
  974.     err = ReadQLSector (fd, buf, sect);
  975.  
  976.     if (err < 0)
  977.         perror ("dump block: read(): ");
  978.     if (flag == 0)
  979.     {
  980.         p = buf;
  981.         for (k = 0; k < 32; k++)
  982.         {
  983.         printf ("%03lx : ", k * 16 + fpos);
  984.  
  985.         for (j = 0; j < 16; j++)
  986.         {
  987.             printf (" %02x", *p++);
  988.         }
  989.         fputc ('\t', stdout);
  990.         p -= 16;
  991.  
  992.         for (j = 0; j < 16; j++, p++)
  993.         {
  994.             printf ("%c", isprint (*p) ? *p : '.');
  995.         }
  996.         fputc ('\n', stdout);
  997.         }
  998.     }
  999.     else
  1000.     {
  1001.         write (1, buf, 512);
  1002.     }
  1003.     }
  1004. }
  1005.  
  1006. int read_cluster (void *p, int num)
  1007. {
  1008.     int i, sect;
  1009.     int r = 0;
  1010.  
  1011.     for (i = 0; i < allocblock; i++)
  1012.     {
  1013.     sect = num * allocblock + i;
  1014.     r = ReadQLSector (fd, (char *) p + i * GSSIZE, sect);
  1015.     }
  1016.     return r;
  1017. }
  1018.  
  1019. void write_cluster (void *p, int num)
  1020. {
  1021.     int i, sect;
  1022.  
  1023.     for (i = 0; i < allocblock; i++)
  1024.     {
  1025.     sect = num * allocblock + i;
  1026.     WriteQLSector (fd, (char *) p + i * GSSIZE, sect);
  1027.     }
  1028. }
  1029.  
  1030. void read_b0fat (int argconv)
  1031. {
  1032.     static const union
  1033.     {
  1034.     char c[4];
  1035.     long l;
  1036.     }
  1037.     ql5 = {"QL5"};
  1038.  
  1039.     err = ReadQLSector (fd, b0, 0);
  1040.  
  1041.     if ((*((long *) b0->q5a_id) & 0xffffff) != ql5.l)
  1042.     {
  1043.     fprintf (stderr, "\nNot an SMS disk %.4s %lx !!!\n",
  1044.          b0->q5a_id, *(long *) b0->q5a_id);
  1045.     exit (0);
  1046.     }
  1047.  
  1048.     ql5a = b0->q5a_id[3] == 'A';
  1049.  
  1050.     gtracks = swapword (b0->q5a_trak);
  1051.     gsectors = swapword (b0->q5a_strk);
  1052.     gspcyl = swapword (b0->q5a_scyl);
  1053.     gsides = gspcyl / gsectors;
  1054.     goffset = swapword (b0->q5a_soff);
  1055.     bleod = swapword (b0->q5a_eodbl);
  1056.     byeod = swapword (b0->q5a_eodby);
  1057.     allocblock = swapword (b0->q5a_allc);
  1058.     gclusters = gtracks * gspcyl / allocblock;
  1059.  
  1060.     make_convtable (argconv);
  1061.     read_fat ();
  1062.  
  1063. }
  1064.  
  1065. void write_b0fat (void)
  1066. {
  1067.     int i;
  1068.  
  1069.     b0->q5a_mupd = swaplong (swaplong (b0->q5a_mupd) + 1);
  1070.  
  1071.     for (i = 0; fat_file (i) == 0xf80; i++)
  1072.     {
  1073.     write_cluster ((unchar *) b0 + i * allocblock * GSSIZE, i);
  1074.     }
  1075. }
  1076.  
  1077.  
  1078. void read_fat (void)
  1079. {
  1080.     int i;
  1081.  
  1082.     for (i = 0; fat_file (i) == 0xf80; i++)
  1083.     read_cluster ((unchar *) b0 + i * allocblock * GSSIZE, i);
  1084. }
  1085.  
  1086. short CheckFileName (QLDIR * ent, char *fname)
  1087. {
  1088.     short match = 0;
  1089.     char c0, c1;
  1090.     int i, len;
  1091.  
  1092.     len = strlen (fname);
  1093.     if (swapword (ent->d_szname) == len)
  1094.     {
  1095.     match = 1;
  1096.     for (i = 0; i < len; i++)
  1097.     {
  1098.         c0 = *(ent->d_name + i);
  1099.         c0 = tolower (c0);
  1100.         c1 = tolower (fname[i]);
  1101.  
  1102.         if (c0 != c1)
  1103.         {
  1104.         if (!tranql || !(c1 == '.' && c0 == '_'))
  1105.         {
  1106.             match = 0;
  1107.             break;
  1108.         }
  1109.         }
  1110.     }
  1111.     }
  1112.     return match;
  1113. }
  1114. #ifndef VMS
  1115. # pragma argsused
  1116. #endif
  1117.  
  1118. /* ARGSUSED */
  1119. int FindName (QLDIR * e, int fileno, void *llist)
  1120. {
  1121.     int res;
  1122.     char **mlist = (char **) llist;
  1123.  
  1124.     if ((res = CheckFileName (e, mlist[0])) != 0)
  1125.     {
  1126.     memcpy ((QLDIR *) mlist[1], e, sizeof (QLDIR));
  1127.     }
  1128.     return res;
  1129. }
  1130.  
  1131. long int match_file (char *fname, QLDIR ** ent, SDL ** sdl)
  1132. {
  1133.     static QLDIR sd;
  1134.     int d, match = 0;
  1135.     long r = 0L;
  1136.  
  1137.     if (sdl)
  1138.     {
  1139.     *sdl = NULL;
  1140.     }
  1141.     for (d = 1; d < maxdir (); d++)
  1142.     {
  1143.     if ((match = CheckFileName (pdir + d, fname)) != 0)
  1144.     {
  1145.         if (ent)
  1146.         {
  1147.         *ent = pdir + d;
  1148.         }
  1149.         r = d;
  1150.         break;
  1151.     }
  1152.     }
  1153.  
  1154.     if (match == 0)
  1155.     {
  1156.     SDL *sl;
  1157.  
  1158.     memset (&sd, 0, 64);
  1159.     for (sl = SList; sl; sl = sl->next)
  1160.     {
  1161.         if (sl->flen > 64 && strnicmp (fname, sl->name, sl->szname) == 0
  1162.         && strlen(fname) != sl->szname)
  1163.         {
  1164.         void *llist[3];
  1165.  
  1166.         llist[0] = fname;
  1167.         llist[1] = &sd;
  1168.         llist[2] = NULL;
  1169.  
  1170.         if ((match = RecurseDir (sl->fileno, sl->flen, llist,
  1171.                      FindName)) != 0)
  1172.         {
  1173.             r = FileXDir (sd.d_fileno);
  1174.             if (ent)
  1175.             {
  1176.             *ent = &sd;
  1177.             }
  1178.             if (sdl)
  1179.             {
  1180.             *sdl = sl;
  1181.             }
  1182.             break;
  1183.         }
  1184.         }
  1185.     }
  1186.     }
  1187.     return (r);
  1188. }
  1189.  
  1190. char *MakeQLName (char *fn, short *n)
  1191. {
  1192.     char *p, *q;
  1193.  
  1194.     if ((p = strrchr (fn, '/')) != NULL)
  1195.     {
  1196.     p++;
  1197.     }
  1198.     else if ((p = strrchr (fn, '\\')) != NULL)
  1199.     {
  1200.     p++;
  1201.     }
  1202.  
  1203.     if (p == NULL)
  1204.     p = fn;
  1205.     q = strdup (p);
  1206.  
  1207.     *n = min (strlen (q), 36);
  1208.     *(q + (*n)) = 0;
  1209.  
  1210.     if (tranql)
  1211.     {
  1212.     for (p = q; *p; p++)
  1213.     {
  1214.         if (*p == '.')
  1215.         *p = '_';
  1216.     }
  1217.     }
  1218.  
  1219.     return q;
  1220. }
  1221.  
  1222. SDL *CheckDirLevel (char *qlnam, short n)
  1223. {
  1224.     SDL *sl;
  1225.  
  1226.     for (sl = SList; sl; sl = sl->next)
  1227.     {
  1228.     if (n > sl->szname + 1)
  1229.     {
  1230.         if (strnicmp (qlnam, sl->name, sl->szname) == 0)
  1231.         {
  1232.         if (*(qlnam + sl->szname) == '_')
  1233.         {
  1234.             break;
  1235.         }
  1236.         }
  1237.     }
  1238.     }
  1239.     return sl;
  1240. }
  1241.  
  1242. int AllocNewSubDirCluster (long flen, ushort fileno)
  1243. {
  1244.     short i;
  1245.     short seqno;
  1246.     unchar *p;
  1247.  
  1248.     seqno = flen / (GSSIZE * allocblock);
  1249.  
  1250.     if ((i = alloc_new_cluster (fileno, seqno, 0)) != -1)
  1251.     {
  1252.     p = xmalloc (GSSIZE * allocblock);
  1253.     write_cluster (p, i);
  1254.     }
  1255.     return i;
  1256. }
  1257.  
  1258. QLDIR *GetNewDirEntry (SDL * sdl, int *filenew, int *nblock, short *diroff)
  1259. {
  1260.     int i;
  1261.     int hole;
  1262.     int offset;
  1263.     QLDIR *ent;
  1264.  
  1265.     if (sdl == NULL)
  1266.     {
  1267.     offset = 1;
  1268.     while ((swaplong ((pdir + offset)->d_length) +
  1269.         swapword ((pdir + offset)->d_szname) > 0)
  1270.            && (offset < maxdir ()))
  1271.     {
  1272.         offset++;
  1273.     }
  1274.  
  1275.     if (offset >= maxdir ())
  1276.     {
  1277.         hole = 0;
  1278.         offset = maxdir ();
  1279.     }
  1280.     else
  1281.     {
  1282.         hole = 1;
  1283.     }
  1284.  
  1285.     if ((byeod == 0) && ((bleod % allocblock) == 0) && !hole)
  1286.     {
  1287.         i = alloc_new_cluster (0, block_max, 0);
  1288.         if (i < 0)
  1289.         {
  1290.         fprintf (stderr, "write file: no free cluster\n");
  1291.         exit (1);
  1292.         }
  1293.         *nblock = *nblock + 1;
  1294.         block_dir[block_max] = i;
  1295.         block_max++;
  1296.     }
  1297.  
  1298.     if (!hole)
  1299.         byeod += 64;
  1300.  
  1301.     if (byeod == GSSIZE)
  1302.     {
  1303.         byeod = 0;
  1304.         bleod += 1;
  1305.     }
  1306.  
  1307.     *filenew = offset;
  1308.     ent = pdir + offset;
  1309.     }
  1310.     else
  1311.     {
  1312.     static QLDIR newent;
  1313.  
  1314.     if ((sdl->flen % GSSIZE * allocblock) == 0)
  1315.     {
  1316.         if (AllocNewSubDirCluster (sdl->flen, sdl->fileno))
  1317.         {
  1318.         *nblock = *nblock + 1;
  1319.         *diroff = sdl->flen;
  1320.         sdl->flen += 64;
  1321.         }
  1322.     }
  1323.     else
  1324.     {
  1325.         COUNT_S nf;
  1326.  
  1327.         nf.nfiles = nf.rflag = nf.freed = nf.indir = 0;
  1328.         RecurseDir (sdl->fileno, sdl->flen, &nf,
  1329.             (int (*) (QLDIR *, int, void *))CountDir);
  1330.  
  1331.         if ((sdl->flen - 64) == 64 * nf.nfiles)
  1332.         {
  1333.         *diroff = sdl->flen;
  1334.         sdl->flen += 64;
  1335.         }
  1336.         else
  1337.         {
  1338.         *diroff = 64 * nf.freed;
  1339.         }
  1340.     }
  1341.     i = find_free_cluster ();
  1342.     ent = &newent;
  1343.     *filenew = (i + 0x800);
  1344.     }
  1345.     return ent;
  1346. }
  1347.  
  1348. SDL * AddSlist(QLDIR *entry, int fileno)
  1349. {
  1350.     SDL *sdl;
  1351.     sdl = xmalloc (sizeof (SDL));
  1352.     sdl->flen = swaplong (entry->d_length);
  1353.     sdl->fileno = fileno;
  1354.     sdl->szname = swapword (entry->d_szname);
  1355.     memcpy (sdl->name, entry->d_name, sdl->szname);
  1356.     sdl->next = SList;
  1357.     SList = sdl;
  1358.  
  1359.     return sdl;
  1360.  
  1361. }
  1362.  
  1363. int ProcessSubFile(QLDIR *entry, int fileno, FSBLK *fs)
  1364. {
  1365.  
  1366.     short n = swapword(fs->nde->d_szname);
  1367.     short m = swapword(entry->d_szname);
  1368.  
  1369.     if((m > n + 1) &&
  1370.                 strnicmp(entry->d_name, fs->nde->d_name, n) == 0 &&
  1371.                 *(entry->d_name + n) == '_')
  1372.     {
  1373.         ushort dcl, fcl;
  1374.         QLDIR nent;
  1375.         SDL *nsdl;
  1376.         short i;
  1377.         unchar *buf;
  1378.         long cwdlen;
  1379.  
  1380.         fcl = FindCluster(fileno, 0);
  1381.         nent = *entry;
  1382.  
  1383.         /* If its a root entry, this removes it */
  1384.  
  1385.         entry->d_length = 0;
  1386.         entry->d_szname = 0;
  1387.  
  1388.         if((nsdl = CheckDirLevel(entry->d_name, m)) != NULL)
  1389.         {
  1390.         /* If a sub-dir, this does */
  1391.         UpdateSubEntry(entry, nsdl, 0);
  1392.         }
  1393.  
  1394.         for (i = 0; i < gclusters; i++)
  1395.         {
  1396.         if(fat_file (i) == fileno)
  1397.         {
  1398.             set_fat_file(i, fcl+0x800);
  1399.         }
  1400.         }
  1401.         nent.d_fileno = swapword(fcl+0x801);
  1402.         /*
  1403.          * fs->fnew is the file no (start cluster (+0x800))
  1404.          * of directory
  1405.              */
  1406.  
  1407.         /* Now write nent to new-ish directory */
  1408.  
  1409.         buf = xmalloc(GSSIZE * allocblock);
  1410.         cwdlen = swaplong(fs->nde->d_length);
  1411.         dcl = fs->fnew;
  1412.         if((cwdlen % GSSIZE * allocblock) == 0)
  1413.         {
  1414.         dcl = alloc_new_cluster(dcl,
  1415.                     cwdlen / (GSSIZE * allocblock), 0);
  1416.         *(fs->nptr) = *(fs->nptr) + 1;
  1417.         }
  1418.         else if(cwdlen > 64)
  1419.         {
  1420.         read_cluster(buf, dcl);
  1421.         }
  1422.         memcpy(buf+cwdlen, &nent, 64);
  1423.         write_cluster(buf, dcl);
  1424.         fs->nde->d_length = swaplong(cwdlen + 64);
  1425.  
  1426.     }
  1427.     else if(entry->d_type == 255)
  1428.     {
  1429.         RecurseDir(fileno, swaplong(entry->d_length), fs,
  1430.            (int (*) (QLDIR *, int, void *))ProcessSubFile);
  1431.     }
  1432.  
  1433.     return 0;
  1434. }
  1435.  
  1436. int MoveSubFiles(FSBLK *fs)
  1437. {
  1438.     QLDIR *entry;
  1439.     short d;
  1440.  
  1441.     for (d = 1; d < maxdir (); d++)
  1442.     {
  1443.     entry = pdir + d;
  1444.     if (swaplong (entry->d_length) + swapword (entry->d_szname) != 0)
  1445.     {
  1446.         ProcessSubFile (entry, d, fs);
  1447.     }
  1448.     }
  1449.     return 0;
  1450. }
  1451.  
  1452. void writefile (char *fn, short dflag)
  1453. {
  1454.     unchar *datbuf;
  1455.     int filenew, i, fl;
  1456.     QLDIR *entry;
  1457.     unsigned long free_sect;
  1458.     long y, qdsize = 0;
  1459.     int enddat;
  1460.     int block = 0, nblock = 0;
  1461.     char *qlnam;
  1462.     short nlen;
  1463.     QLDIR *vers = NULL;
  1464.     SDL *sdl = NULL;
  1465.     short flag = 0;
  1466.     short diroff = 0;
  1467.     short nvers = -1;
  1468.     time_t t;
  1469.     struct stat s;
  1470.     short blksiz = GSSIZE * allocblock;
  1471.  
  1472.     qlnam = MakeQLName (fn, &nlen);
  1473.  
  1474.     if(dflag != 255)
  1475.     {
  1476.     if(stat(fn, &s) == 0)
  1477.     {
  1478.         if(s.st_size == 16)
  1479.         {
  1480.         int fd;
  1481.         char tbuf[16];
  1482.  
  1483.         if((fd = open(fn, O_RDONLY|O_BINARY)) > -1)
  1484.         {
  1485.             read(fd, tbuf, 16);
  1486.             if(memcmp(tbuf, QLDIRSTRING,16) == 0)
  1487.             {
  1488.             dflag = 255;
  1489.             }
  1490.             close (fd);
  1491.         }
  1492.         }
  1493.     }
  1494.     else
  1495.     {
  1496.         fprintf(stderr, "Can't stat file %s\n", fn);
  1497.         exit(0);
  1498.     }
  1499.     }
  1500.  
  1501.  
  1502.     if (list)
  1503.     {
  1504.     fputs (fn, stderr);
  1505.     }
  1506.  
  1507.     if ((fl = match_file (qlnam, &vers, &sdl)) != 0)
  1508.     {
  1509.     if (dflag == 255)
  1510.     {
  1511.         fputs ("Exists\n", stderr);
  1512.         exit (0);
  1513.     }
  1514.     else
  1515.     {
  1516.         if (OWopt != 'A')
  1517.         {
  1518.         fprintf (stderr, "file %s exists, overwrite [Y/N/A/Q] : ", qlnam);
  1519.         do
  1520.         {
  1521.             OWopt = getch ();
  1522.             OWopt = toupper (OWopt);
  1523.         }
  1524.         while (strchr ("\003ANYQ", OWopt) == NULL);
  1525.         fprintf (stderr, "%c\n", OWopt);
  1526.         if (OWopt == 'N')
  1527.         {
  1528.             return;
  1529.         }
  1530.         else
  1531.         {
  1532.             if (OWopt == 'Q' || OWopt == 3)
  1533.             {
  1534.             exit (2);
  1535.             }
  1536.         }
  1537.         }
  1538.         nvers = swapword (vers->d_version);
  1539.         del_file (fl, vers, sdl);
  1540.     }
  1541.     }
  1542.  
  1543.     if (dflag == 255)
  1544.     {
  1545.     y = 64;
  1546.     }
  1547.     else
  1548.     {
  1549.  
  1550.     if ((fl = open (fn, O_RDONLY | O_BINARY)) == -1)
  1551.     {
  1552.         perror ("write file: could not open input file ");
  1553.         exit (1);
  1554.     }
  1555.     y = s.st_size + 64;
  1556.     {
  1557.         long stuff[2];
  1558.         lseek (fl, -8, SEEK_END);
  1559.         read (fl, stuff, 8);
  1560.         if (*stuff == *(long *) "XTcc")
  1561.         {
  1562.         qdsize = *(stuff + 1);
  1563.         }
  1564.     }
  1565.  
  1566.     err = lseek (fl, 0, SEEK_SET);    /* reposition to zero!!! */
  1567.     if (err < 0)
  1568.         perror ("write file: lseek() on input file : ");
  1569.     }
  1570.  
  1571.     free_sect = swapword (b0->q5a_free);
  1572.     if (y > free_sect * GSSIZE)
  1573.     {
  1574.     fprintf (stderr, " file %s too large (%ld %ld)\n", fn, y, free_sect);
  1575.     exit (1);
  1576.     }
  1577.  
  1578.     if (sdl == NULL)
  1579.     {
  1580.     sdl = CheckDirLevel (qlnam, strlen(qlnam));
  1581.     }
  1582.  
  1583.     entry = GetNewDirEntry (sdl, &filenew, &nblock, &diroff);
  1584.     memset (entry, '\0', 64);
  1585.  
  1586.     if (filenew & 0x800)
  1587.     {
  1588.     flag = filenew - 0x800;
  1589.     }
  1590.     else
  1591.     {
  1592.     flag = 0;
  1593.     }
  1594.  
  1595.     entry->d_length = swaplong (y);
  1596.     entry->d_fileno = swapword (filenew + 1);
  1597.  
  1598.     if (dflag != 255)
  1599.     {
  1600.     if (qdsize == 0)
  1601.     {
  1602.         entry->d_type = 0;
  1603.         entry->d_datalen = 0;
  1604.     }
  1605.     else
  1606.     {
  1607.         entry->d_type = 1;
  1608.         entry->d_datalen = qdsize;    /* big endian already */
  1609.     }
  1610.     }
  1611.  
  1612.     memcpy (entry->d_name, qlnam, nlen);
  1613.     entry->d_szname = swapword (nlen);
  1614.  
  1615.     t = time (NULL) + TIME_DIFF + timeadjust;
  1616.  
  1617.     entry->d_update = entry->d_backup = swaplong (t);
  1618.     nvers++;
  1619.     entry->d_version = swapword (nvers);
  1620.  
  1621.     if (dflag == 255)
  1622.     {
  1623.     filenew = alloc_new_cluster (filenew, 0, flag);
  1624.     nblock++;
  1625.     }
  1626.     else
  1627.     {
  1628.     int nwr = 0;
  1629.  
  1630.     datbuf = xmalloc(blksiz);
  1631.     enddat = (y < blksiz) ? y : blksiz;
  1632.     err = read (fl, datbuf + 64, enddat - 64);
  1633.  
  1634.     memcpy (datbuf, entry, 64);
  1635.     for (block = 0; y > 0;)
  1636.     {
  1637.         i = alloc_new_cluster (filenew, block, flag);
  1638.         flag = 0;
  1639.  
  1640.         if (i < 0)
  1641.         {
  1642.         fprintf (stderr, " filewrite failed : no free cluster\n");
  1643.         exit (1);
  1644.         }
  1645.         block++;
  1646.         nblock++;
  1647.  
  1648.         if(list)
  1649.         {
  1650.         nwr += err;
  1651.         fprintf(stderr,"%8d\b\b\b\b\b\b\b\b", nwr); fflush(stderr);
  1652.         }
  1653.  
  1654.         write_cluster (datbuf, i);
  1655.  
  1656.         y -= blksiz;
  1657.  
  1658.         err = read (fl, datbuf, blksiz);
  1659.         if (err < 0)
  1660.         perror ("write file: read on input file:");
  1661.     }
  1662.     close (fl);
  1663.     free(datbuf);
  1664.     }
  1665.  
  1666.     free (qlnam);
  1667.  
  1668.     b0->q5a_eodbl = swapword (bleod);
  1669.     b0->q5a_eodby = swapword (byeod);
  1670.  
  1671.     if (dflag == 255)
  1672.     {
  1673.     FSBLK fs;
  1674.     fs.nde = entry;
  1675.     fs.nptr = &nblock;
  1676.     fs.fnew = filenew;
  1677.     MoveSubFiles (&fs);
  1678.     entry->d_type = 255;
  1679.     }
  1680.  
  1681.     b0->q5a_free = swapword (free_sect - nblock * allocblock);
  1682.  
  1683.     write_b0fat ();
  1684.     dir_write_back (entry, sdl, &diroff);
  1685.  
  1686.     if (sdl)
  1687.     {
  1688.     SDL *msdl = NULL;
  1689.     QLDIR *mentry;
  1690.     char dirname[40];
  1691.  
  1692.     memcpy (dirname, sdl->name, sdl->szname);
  1693.     *(dirname + sdl->szname) = '\0';
  1694.     if ((fl = match_file (dirname, &mentry, &msdl)) != 0)
  1695.     {
  1696.         mentry->d_length = swaplong (sdl->flen);
  1697.         mentry->d_update = entry->d_update;
  1698.         dir_write_back (mentry, msdl, NULL);
  1699.     }
  1700.     }
  1701.  
  1702.     if(list)
  1703.     fputc ('\n', stderr);
  1704.  
  1705.     if(dflag == 255)
  1706.     {
  1707.     AddSlist(entry, FileXDir(entry->d_fileno));
  1708.     }
  1709. }
  1710.  
  1711. #ifndef VMS
  1712. #pragma argsused
  1713. #endif
  1714. /* ARGSUSED */
  1715.  
  1716. int AddDirEntry (QLDIR * entry, int fileno, void *flag)
  1717. {
  1718.     if (entry->d_type == 255)
  1719.     {
  1720.     SDL *sdl = AddSlist(entry, fileno);
  1721.     RecurseDir (fileno, sdl->flen, NULL, AddDirEntry);
  1722.     }
  1723.     return 0;
  1724. }
  1725.  
  1726. void BuildSubList (void)
  1727. {
  1728.     short d;
  1729.     QLDIR *entry;
  1730.     long flen;
  1731.  
  1732.     for (d = 1; d < maxdir (); d++)
  1733.     {
  1734.     entry = pdir + d;
  1735.     flen = swaplong (entry->d_length);
  1736.  
  1737.     if (flen + swapword (entry->d_szname) != 0)
  1738.     {
  1739.         if (entry->d_type == 255)
  1740.         {
  1741.         AddDirEntry (entry, d, NULL);
  1742.         }
  1743.     }
  1744.     }
  1745. }
  1746.  
  1747. void read_dir (void)
  1748. {
  1749.     int i, fn, cl;
  1750.  
  1751.     for (i = 0; i < gclusters; i++)
  1752.     {
  1753.     cl = fat_cl (i);
  1754.     fn = fat_file (i);
  1755.  
  1756.     if (fn == 0)
  1757.     {
  1758.         block_dir[block_max] = i;
  1759.         block_max++;
  1760.         read_cluster ((char *) pdir + GSSIZE * allocblock * cl, i);
  1761.     }
  1762.     }
  1763.     BuildSubList ();
  1764. }
  1765.  
  1766. void print_map (void)
  1767. {
  1768.     int i, fn, cl;
  1769.     QLDIR *entry;
  1770.     short flag;
  1771.  
  1772.     printf ("\nblock\tfile\tpos\n\n");
  1773.  
  1774.     for (i = 0; i < gclusters; i++)
  1775.     {
  1776.     cl = fat_cl (i);
  1777.     fn = fat_file (i);
  1778.  
  1779.     printf ("%d\t%d\t%d\t(%03x, %03x) ", i, fn, cl, fn, cl);
  1780.  
  1781.     if ((fn & 0xFF0) == 0xFD0 && (fn & 0xf) != 0xF)
  1782.     {
  1783.         printf ("erased %2d\t", fn & 0xF);
  1784.     }
  1785.  
  1786.     entry = NULL;
  1787.     switch (fn)
  1788.     {
  1789.         case 0x000:
  1790.         printf ("directory");
  1791.         break;
  1792.         case 0xF80:
  1793.         printf ("map");
  1794.         break;
  1795.         case 0xFDF:
  1796.         printf ("unused");
  1797.         break;
  1798.         case 0xFEF:
  1799.         printf ("bad");
  1800.         break;
  1801.         case 0xFFF:
  1802.         printf ("not existent");
  1803.         break;
  1804.         default:
  1805.         entry = GetEntry (fn);
  1806.         break;
  1807.     }
  1808.     if (entry)
  1809.     {
  1810.         flag = 2;
  1811.         print_entry (entry, fn, &flag);
  1812.     }
  1813.     else
  1814.     {
  1815.         putc ('\n', stdout);
  1816.     }
  1817.     }
  1818. }
  1819.  
  1820. void set_header (int ni, long h, QLDIR * entry, SDL * sdl)
  1821. {
  1822.     int i;
  1823.     unchar *b = xmalloc (allocblock * 512);
  1824.  
  1825.     if (swaplong (entry->d_length) + swapword (entry->d_szname) == 0)
  1826.     {
  1827.     fprintf (stderr, "file deleted ??\n");
  1828.     exit (1);
  1829.     }
  1830.  
  1831.     i = FindCluster (ni, 0);
  1832.  
  1833.     read_cluster (b, i);
  1834.     entry->d_type = ((QLDIR *) b)->d_type = 1;
  1835.     entry->d_datalen = ((QLDIR *) b)->d_datalen = swaplong (h);
  1836.     write_cluster (b, i);
  1837.     free (b);
  1838.     dir_write_back (entry, sdl, NULL);
  1839. }
  1840.  
  1841. void dir_write_back (QLDIR * entry, SDL * sdl, short *off)
  1842. {
  1843.  
  1844.     if (sdl)
  1845.     {
  1846.     UpdateSubEntry (entry, sdl, off);
  1847.     }
  1848.     else
  1849.     {
  1850.     int i;
  1851.  
  1852.     for (i = 0; i < block_max; i++)
  1853.         write_cluster (pdir + DIRSBLK * allocblock * i, block_dir[i]);
  1854.     }
  1855. }
  1856.  
  1857. int find_free_cluster (void)
  1858. {
  1859.     short fflag, i;
  1860.  
  1861.     for (i = lac + 1; i < gclusters; i++)
  1862.     {
  1863.     fflag = fat_file (i);
  1864.     if ((fflag >> 4) == 0xFD)
  1865.     {
  1866.         break;
  1867.     }
  1868.     }
  1869.     return (i < gclusters ? i : -1);
  1870. }
  1871.  
  1872. int alloc_new_cluster (int fnum, int iblk, short flag)
  1873. {
  1874.     short i;
  1875.  
  1876.     if (flag)
  1877.     {
  1878.     i = flag;
  1879.     }
  1880.     else
  1881.     {
  1882.     i = find_free_cluster ();
  1883.     }
  1884.  
  1885.     if (i != -1)
  1886.     {
  1887.     set_fat_file (i, fnum);
  1888.     set_fat_cl (i, iblk);
  1889.     lac = i;
  1890.     }
  1891.     return i;
  1892. }
  1893.  
  1894.  
  1895. void free_cluster (long i)
  1896. {
  1897.     int fn, dfn;
  1898.  
  1899.     if (i > 0)
  1900.     {
  1901.     fn = fat_file (i);
  1902.     dfn = 0xFD0 | (0xf & fn);
  1903.     set_fat_file (i, dfn);
  1904.     }
  1905.     else
  1906.     {
  1907.     fprintf (stderr, "freeing cluster 0 ???!!!\n");
  1908.     exit (1);
  1909.     }
  1910. }
  1911.  
  1912. void format (char *frmt, char *argfname)
  1913. {
  1914.     static char ltp_dd[] =
  1915.     {
  1916.     0, 3, 6, 0x80, 0x83, 0x86, 1, 4,
  1917.     7, 0x81, 0x84, 0x87, 2, 5, 8, 0x82, 0x85, 0x88
  1918.     };
  1919.  
  1920.     static char ptl_dd[] =
  1921.     {
  1922.     0, 6, 0x0c, 1, 7, 0x0d,
  1923.     2, 8, 0x0e, 3, 9, 0x0f, 4, 0x0a, 0x10, 5, 0x0b, 0x11
  1924.     };
  1925.  
  1926.     static char ltp_hd[] =
  1927.     {
  1928.     0, 2, 4, 6, 8, 0xa, 0xc, 0xe, 0x10,
  1929.     0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90,
  1930.     1, 3, 5, 7, 9, 0xb, 0xd, 0xf, 0x11,
  1931.     0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91
  1932.     };
  1933.  
  1934.     int cls;
  1935.     time_t t;
  1936.  
  1937.     t = time (NULL);
  1938.     b0->q5a_rand = swapword (t & 0xffff);
  1939.     if(argfname == NULL)
  1940.     {
  1941.     argfname = "";
  1942.     }
  1943.  
  1944.     ZeroSomeSectors(fd, *frmt);
  1945.  
  1946.     if (*frmt == 'd')        /* 720 K format */
  1947.     {
  1948.     ql5a = 1;
  1949.     memcpy (b0, "QL5A          ", 14);
  1950.     memcpy (b0->q5a_mnam, argfname, (strlen (argfname) <= 10 ?
  1951.                      strlen (argfname) : 10));
  1952.     memcpy (b0->q5a_lgph, ltp_dd, 18);
  1953.     memcpy (b0->q5a_phlg, ptl_dd, 18);
  1954.  
  1955.     gsides = 2;
  1956.     b0->q5a_trak = swapword (80);
  1957.     gtracks = 80;
  1958.     b0->q5a_strk = swapword (9);
  1959.     gsectors = 9;
  1960.     b0->q5a_scyl = swapword (18);
  1961.     gspcyl = 18;
  1962.     goffset = 5;
  1963.     b0->q5a_soff = swapword (5);
  1964.     b0->q5a_eodbl = 0;
  1965.     b0->q5a_eodby = swapword (64);
  1966.     b0->q5a_free = swapword (1434);
  1967.     b0->q5a_good = b0->q5a_totl = swapword (1440);
  1968.     b0->q5a_allc = swapword (3);
  1969.     allocblock = 3;
  1970.  
  1971.     set_fat_file (0, 0xF80);    /* FAT entry for FAT */
  1972.     set_fat_cl (0, 0);
  1973.     set_fat_file (1, 0);    /*  ...  for directory */
  1974.     set_fat_cl (1, 0);
  1975.     gclusters = gtracks * gspcyl / allocblock;
  1976.     for (cls = 2; cls < gclusters; cls++)
  1977.     {            /* init rest of FAT */
  1978.         set_fat_file (cls, 0xFDF);
  1979.         set_fat_cl (cls, 0xFFF);
  1980.     }
  1981.     }
  1982.     else if (*frmt == 'h')
  1983.     {
  1984.     memcpy (b0, "QL5B          ", 14);
  1985.     ql5a = 0;
  1986.  
  1987.     memcpy (b0->q5a_mnam, argfname,
  1988.         (strlen (argfname) <= 10 ? strlen (argfname) : 10));
  1989.     memcpy (b0->q5a_lgph, ltp_hd, 36);
  1990.  
  1991.     gsides = 2;
  1992.     b0->q5a_trak = swapword (80);
  1993.     gtracks = 80;
  1994.     b0->q5a_strk = swapword (18);
  1995.     gsectors = 18;
  1996.     b0->q5a_scyl = swapword (36);
  1997.     gspcyl = 36;
  1998.     goffset = 2;
  1999.     b0->q5a_soff = swapword (2);
  2000.     b0->q5a_eodbl = 0;
  2001.     b0->q5a_eodby = swapword (64);
  2002.     b0->q5a_free = swapword (2871);
  2003.     b0->q5a_good = b0->q5a_totl = swapword (2880);
  2004.     b0->q5a_allc = swapword (3);
  2005.     allocblock = 3;
  2006.  
  2007.     set_fat_file (0, 0xF80);    /* FAT entry for FAT */
  2008.     set_fat_cl (0, 0);
  2009.     set_fat_file (1, 0xf80);
  2010.     set_fat_cl (1, 1);
  2011.     set_fat_file (2, 0);    /*  ...  for directory */
  2012.     set_fat_cl (2, 0);
  2013.  
  2014.     gclusters = gtracks * gspcyl / allocblock;
  2015.     for (cls = 3; cls < gclusters; cls++)
  2016.     {            /* init rest of FAT */
  2017.         set_fat_file (cls, 0xFDF);
  2018.         set_fat_cl (cls, 0xFFF);
  2019.     }
  2020.     }
  2021.     make_convtable (0);
  2022.     write_b0fat ();
  2023. }
  2024.  
  2025. int main (int ac, char **av)
  2026. {
  2027.     int i;
  2028.     QLDIR *entry;
  2029.     SDL *sdl;
  2030.     int mode = O_RDONLY;
  2031.     int dofmt = 0;
  2032.     long np1 = 0, np2 = 0;
  2033.  
  2034.     if (ac < 2)
  2035.     {
  2036.     usage ("too few parameters");
  2037.     }
  2038.  
  2039.     for (i = 2; i < ac; i++)
  2040.     {
  2041.     if ((av[i][0] == '-')
  2042. #ifdef DOS_LIKE
  2043.         || (av[i][0] == '/')
  2044. #endif
  2045.         )
  2046.     {
  2047.         switch (av[i][1])
  2048.         {
  2049.         case 'f':
  2050.             dofmt = i;
  2051.         case 'x':
  2052.         case 'r':
  2053.         case 'w':
  2054.         case 'W':
  2055.         case 'M':
  2056.             mode = O_RDWR;
  2057.             i = ac;
  2058.             break;
  2059.         }
  2060.     }
  2061.     }
  2062.  
  2063.     fd = OpenQLDevice (av[1], mode);
  2064.  
  2065.     if ((int) fd < 0)
  2066.     {
  2067.     perror ("could not open image");
  2068.     usage ("image file not opened");
  2069.     }
  2070.  
  2071.     timeadjust = GetTimeZone ();
  2072.  
  2073.     if ((b0 = xmalloc (GSSIZE * MAXALB)) != NULL)
  2074.     {
  2075.     if (dofmt)
  2076.     {
  2077.         format (av[dofmt] + 2, av[dofmt + 1]);
  2078.         CloseQLDevice (fd);
  2079.         exit (0);
  2080.     }
  2081.  
  2082.     read_b0fat (0);
  2083.     pdir = xmalloc (GSSIZE * allocblock * (bleod + 6));
  2084.     read_dir ();
  2085.  
  2086.     for (i = 2; i < ac; i++)
  2087.     {
  2088.         char c;
  2089.  
  2090.         if (av[i][0] == '-')
  2091.         {
  2092.         OWopt = 0;
  2093.         switch (c = av[i][1])
  2094.         {
  2095.             case 'l':
  2096.             list = 1;
  2097.             break;
  2098.             case 't':
  2099.             tranql ^= 1;
  2100.             break;
  2101.             case 'U':
  2102.             case 'u':
  2103.             if (av[i][2])
  2104.             {
  2105.                 np1 = atol (av[i] + 2);
  2106.             }
  2107.             else
  2108.             {
  2109.                 i++;
  2110.                 np1 = atol (av[i]);
  2111.             }
  2112.             dump_cluster (np1, c == 'U');
  2113.             break;
  2114.             case 'd':
  2115.             print_dir (0);
  2116.             break;
  2117.             case 'q':
  2118.             dump_dir (0);
  2119.             break;
  2120.             case 's':
  2121.             print_dir (1);
  2122.             break;
  2123.             case 'i':
  2124.             print_info ();
  2125.             break;
  2126.             case 'm':
  2127.             print_map ();
  2128.             break;
  2129.             case 'c':
  2130.             make_convtable (1);
  2131.             break;
  2132.             case 'n':
  2133.             i++;
  2134.             np1 = match_file (av[i], &entry, NULL);
  2135.             if (np1)
  2136.             {
  2137.                 cat_file (np1, entry);
  2138.             }
  2139.             else
  2140.             {
  2141.                 fprintf (stderr, "Invalid file\n");
  2142.             }
  2143.             break;
  2144.             case 'W':
  2145.             OWopt = 'A';
  2146.             case 'w':
  2147.             while (av[i + 1] && *av[i + 1] != '-')
  2148.             {
  2149.                 i++;
  2150.                 writefile (av[i], 0);
  2151.             }
  2152.             break;
  2153.             case 'r':
  2154.             i++;
  2155.             np1 = match_file (av[i], &entry, &sdl);
  2156.             if (np1)
  2157.             {
  2158.                 del_file (np1, entry, sdl);
  2159.             }
  2160.             break;
  2161.             case 'M':
  2162.             i++;
  2163.             writefile (av[i], 255);
  2164.             break;
  2165.  
  2166.             case 'x':
  2167.             i++;
  2168.             np1 = match_file (av[i], &entry, &sdl);
  2169.             if (np1)
  2170.             {
  2171.                 i++;
  2172.                 np2 = strtol (av[i], NULL, 0);
  2173.                 if (np2)
  2174.                 {
  2175.                 set_header (np1, np2, entry, sdl);
  2176.                 }
  2177.             }
  2178.             break;
  2179.             default:
  2180.             usage ("bad option");
  2181.             break;
  2182.         }
  2183.         }
  2184.         else
  2185.         {
  2186.         np1 = match_file (av[i], &entry, NULL);
  2187.         if (np1)
  2188.         {
  2189.             cat_file (np1, entry);
  2190.         }
  2191.         }
  2192.     }
  2193.     CloseQLDevice (fd);
  2194.     }
  2195.     return (0);
  2196. /* This is to repvent compiler warning !! */
  2197. /* NOTREACHED */
  2198.     (void)rcsid;
  2199. }
  2200.